﻿using System;
using System.Net;
#if SL4BETA
using System.Windows.Interop;
#else
using System.Windows.Interop;
using System.Runtime.InteropServices.Automation;
#endif
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;


/* From http://silverlightcom.codeplex.com */

namespace Silverlight.Mainline.InjectionHelper.IO
{
    public enum AdoState
    {
        Closed = 0,         //adStateClosed: The object is closed
        Open = 1,           //adStateOpen: The object is open
        Connecting = 2,     //adStateConnecting: The object is connecting
        Executing = 4,      //adStateExecuting: The object is executing a command
        Fetching = 8        //adStateFetching: The rows of the object are being retrieved
    }

    public class AdoFileStream : System.IO.Stream
    {
        private dynamic stream;
        private string path;
        private string username;
        private string password;

        public AdoFileStream(string path, FileMode mode)
            : this(path, mode, FileAccess.ReadWrite) { }

        public AdoFileStream(string path, FileMode mode, FileAccess access)
            : this(path, mode, access, "", "") { }

        public AdoFileStream(string path, FileMode mode, FileAccess access, string username, string password)
        {
            bool exist = File.Exists(path);
            if (!exist && FileMode == System.IO.FileMode.Open)
                throw new System.IO.FileNotFoundException("File: {0} could not be found.");
            if (exist && FileMode == System.IO.FileMode.CreateNew)
                throw new System.IO.IOException(string.Format("File: {0} allready exist.", path));
            if (!exist && FileMode == System.IO.FileMode.CreateNew && access == FileAccess.Read)
                throw new System.ArgumentException(); //TODO: Add some usefull message :P

            this.path = path;
            FileMode = mode;
#if SL4BETA
            stream = ComAutomationFactory.CreateObject("ADODB.Stream");
#else
            stream = AutomationFactory.CreateObject("ADODB.Stream");
#endif
            this.username = username;
            this.password = password;
            Access = access;


            stream.Type = 1;
            stream.Open();
            if (!exist)
                stream.SaveToFile(path, 1);
            stream.LoadFromFile(path);
        }

        public override long Length { get { return stream.Size; } }
        public override long Position
        {
            get { return stream.Position; }
            set { stream.Position = value; }
        }

        public override void Close()
        {
            if (State != AdoState.Closed)
                stream.Close();
        }

        public FileMode FileMode { get; private set; }
        public FileAccess Access { get; private set; }

        public AdoState State { get { return (AdoState)stream.State; } }

        public override bool CanSeek
        {
            get { return true; }
        }

        public override bool CanRead
        {
            get { return Access == FileAccess.ReadWrite || Access == FileAccess.Read; }
        }
        public override bool CanWrite
        {
            get { return Access == FileAccess.ReadWrite || Access == FileAccess.Write; }
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            if (!CanWrite)
                throw new System.NotSupportedException();
            byte[] ib = new byte[count];
            Array.Copy(buffer, ib, count);
            stream.Write(ib);
        }

        public override void Flush()
        {
            if (!CanWrite)
                throw new System.NotSupportedException();
            stream.SaveToFile(path, (int)AdoFileMode.OpenOrCreate);
            stream.Flush();
        }

        public override int ReadByte()
        {
            if (!CanRead)
                throw new System.NotSupportedException();
            return stream.Read(1);
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            if (!CanRead)
                throw new System.NotSupportedException();
            long n = Length - Position;
            if (n > count)
            {
                n = count;
            }
            if (n <= 0)
            {
                return 0;
            }
            byte[] bytes = stream.Read(n);
            Array.Copy(bytes, buffer, bytes.Length);
            return bytes.Length;
        }

        public override long Seek(long offset, System.IO.SeekOrigin origin)
        {
            throw new NotImplementedException();
        }

        public override void SetLength(long value)
        {
            throw new NotImplementedException();
        }

        protected override void Dispose(bool disposing)
        {
            if (State != AdoState.Closed)
            {
                stream.Close();
                stream = null;
            }
            base.Dispose(disposing);
        }
    }
}
